/// Create by kyluzoi
/// Date: 2021-08-18
///
/// Description:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:lottie/lottie.dart';

const Duration _kIndicatorScaleDuration = Duration(milliseconds: 200);

class CustomRefreshHeader extends Header {
  final Key? key;
  final double displacement;
  final Color backgroundColor;

  final LinkHeaderNotifier linkNotifier = LinkHeaderNotifier();

  CustomRefreshHeader({
    this.key,
    this.displacement = 40.0,
    this.backgroundColor = Colors.blue,
    completeDuration = const Duration(milliseconds: 200),
    bool enableHapticFeedback = false,
  }) : super(
    float: false,
    extent: 70.0,
    triggerDistance: 70.0,
    completeDuration: completeDuration == null
        ? Duration(
      milliseconds: 300,
    )
        : completeDuration +
        Duration(
          milliseconds: 300,
        ),
    enableInfiniteRefresh: false,
    enableHapticFeedback: enableHapticFeedback,
  );

  @override
  Widget contentBuilder(BuildContext context,
      RefreshMode refreshState,
      double pulledExtent,
      double refreshTriggerPullDistance,
      double refreshIndicatorExtent,
      AxisDirection axisDirection,
      bool float,
      Duration? completeDuration,
      bool enableInfiniteRefresh,
      bool success,
      bool noMore) {
    linkNotifier.contentBuilder(
        context,
        refreshState,
        pulledExtent,
        refreshTriggerPullDistance,
        refreshIndicatorExtent,
        axisDirection,
        float,
        completeDuration,
        enableInfiniteRefresh,
        success,
        noMore);
    return CustomRefreshHeaderWidget(
      key: key,
      displacement: displacement,
      backgroundColor: backgroundColor,
      linkNotifier: linkNotifier,
    );
  }
}

class CustomRefreshHeaderWidget extends StatefulWidget {
  final double displacement;
  final Color backgroundColor;
  final LinkHeaderNotifier linkNotifier;

  const CustomRefreshHeaderWidget({
    Key? key,
    required this.displacement,
    required this.backgroundColor,
    required this.linkNotifier,
  }) : super(key: key);

  @override
  CustomRefreshHeaderWidgetState createState() {
    return CustomRefreshHeaderWidgetState();
  }
}

class CustomRefreshHeaderWidgetState extends State<CustomRefreshHeaderWidget>
    with TickerProviderStateMixin<CustomRefreshHeaderWidget> {
  static final Animatable<double> _oneToZeroTween =
  Tween<double>(begin: 1.0, end: 0.0);

  RefreshMode get _refreshState => widget.linkNotifier.refreshState;

  double get _pulledExtent => widget.linkNotifier.pulledExtent;

  double get _riggerPullDistance =>
      widget.linkNotifier.refreshTriggerPullDistance;

  Duration? get _completeDuration => widget.linkNotifier.completeDuration;

  AxisDirection get _axisDirection => widget.linkNotifier.axisDirection;

  late AnimationController _scaleController;
  late Animation<double> _scaleFactor;
  late final AnimationController _lottieController;

  @override
  void initState() {
    super.initState();
    _scaleController = AnimationController(vsync: this);
    _scaleFactor = _scaleController.drive(_oneToZeroTween);
    _lottieController = AnimationController(vsync: this);
  }

  @override
  void dispose() {
    _scaleController.dispose();
    _lottieController.dispose();
    super.dispose();
  }

  bool _refreshFinish = false;

  set refreshFinish(bool finish) {
    if (_refreshFinish != finish) {
      if (finish) {
        Future.delayed(_completeDuration! - Duration(milliseconds: 300), () {
          if (mounted) {
            _scaleController.animateTo(1.0, duration: _kIndicatorScaleDuration);
          }
        });
        Future.delayed(_completeDuration! + Duration(milliseconds: 200), () {
          _refreshFinish = false;
          _scaleController.animateTo(0.0, duration: Duration(milliseconds: 10));
        });
      }
      _refreshFinish = finish;
    }
  }

  @override
  Widget build(BuildContext context) {
    bool isVertical = _axisDirection == AxisDirection.down ||
        _axisDirection == AxisDirection.up;
    bool isReverse = _axisDirection == AxisDirection.up ||
        _axisDirection == AxisDirection.left;

    //
    if (!_refreshFinish) {
      _scaleController.animateTo(
          (widget.displacement -
              (_pulledExtent >= widget.displacement
                  ? widget.displacement
                  : _pulledExtent)) /
              widget.displacement,
          duration: Duration());
    }

    if (_refreshState == RefreshMode.refreshed) {
      refreshFinish = true;
    }
    if (_refreshState == RefreshMode.refresh) {
      _lottieController
        ..duration = Duration(milliseconds: 1000)
        ..repeat(period: Duration(milliseconds: 500));
    } else {
      _lottieController.stop();
    }

    return Container(
      height: isVertical
          ? _refreshState == RefreshMode.inactive
          ? 0.0
          : _pulledExtent
          : double.infinity,
      width: !isVertical
          ? _refreshState == RefreshMode.inactive
          ? 0.0
          : _pulledExtent
          : double.infinity,
      child: Stack(
        children: <Widget>[
          Positioned(
            top: isVertical
                ? isReverse
                ? 0.0
                : null
                : 0.0,
            bottom: isVertical
                ? !isReverse
                ? 0.0
                : null
                : 0.0,
            left: !isVertical
                ? isReverse
                ? 0.0
                : null
                : 0.0,
            right: !isVertical
                ? !isReverse
                ? 0.0
                : null
                : 0.0,
            child: Container(
              color: widget.backgroundColor,
              height: widget.displacement + 200,
              // padding: EdgeInsets.only(bottom: 10),
              alignment: Alignment.bottomCenter,
              child: ScaleTransition(
                  scale: _scaleFactor,
                  child: Lottie.asset('images/loading_cat.json',
                      width: 80,
                      height: 80,
                      controller: _lottieController)),
            ),
          ),
        ],
      ),
    );
  }
}
